package cate.game.role.pvp.championrace;

import cate.common.table.d.*;
import cate.common.util.GameResult;
import cate.game.pvp.championrace.ChampionRaceSpecUtils;
import cate.game.pvp.championrace.data.ChampionRaceBetRecord;
import cate.game.pvp.championrace.data.ChampionRaceSpec;
import cate.game.pvp.championrace.dto.ChampionRaceAllBetRecordsData;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.pvp.championrace.msg.ChampionRaceBetDataResp;
import cate.game.role.pvp.championrace.msg.ChampionRaceBetRecordResp;
import cate.game.role.pvp.championrace.vo.ChampionRaceBetRdVO;
import cate.game.role.pvp.championrace.vo.ChampionRaceBetVO;
import com.google.common.collect.Maps;
import easy.java.dev.note.NoteField;
import org.springframework.util.CollectionUtils;

import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static cate.game.client.msg.MsgSender.send;

public class ChampionRaceBet extends RoleDependent {
    @NoteField("竞猜记录")
    public Map<String, ChampionRaceBetVO> rdMap;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (Objects.isNull(rdMap)) {
            rdMap = Maps.newHashMap();
        }
    }

    @Override
    public void onEnter() {
        super.onEnter();
        handleCalBet();
    }

    public void updateNotice(ChampionRaceSpec spec, ChampionRaceBetRecord record) {
        send(role::sendNow, new ChampionRaceBetDataResp(ChampionRaceBetRdVO.of(record), rdMap.get(spec.toString()), rdMap.size(), 0));
    }

    public void handleBet(ChampionRaceBetVO betVO) {
        rdMap.put(betVO.getSpec().toString(), betVO);
    }

    public void handleBetData() {
        ChampionRaceSpec nowSpec = game().pvp.championRace.getSpec();
        ChampionRaceSpec spec = ChampionRaceSpec.of(
                nowSpec.getSeason(),
                nowSpec.getPeriod(),
                (byte) 0,
                nowSpec.getRound()
        );
        ChampionRaceBetRecord r = game().pvp.championRace.getBizHandler().getBetRecord(spec);
        if (r != null) {
            updateNotice(spec, r);
        }
    }

    public void handleBetRwd(ChampionRaceBetRecord betRecord) {
        if (rdMap.isEmpty() || !rdMap.containsKey(betRecord.getSpec().toString())) {
            return;
        }
        ChampionRaceBetVO betVO = rdMap.get(betRecord.getSpec().toString());
        byte res = betVO.handleBetRecord(betRecord);
        if (res > 0) {
            addCoins(betVO.getGetCoins());
            updateNotice(betRecord.getSpec(), betRecord);
        }
    }

    public byte hasBet(ChampionRaceSpec spec) {
        if (!ChampionRaceSpecUtils.isBetRwd(spec)) {
            return 0;
        }
        return Objects.isNull(rdMap.get(spec.toString())) ? (byte) 1 : (byte) 0;
    }

    public void handleCalBet() {
        if (rdMap.isEmpty()) {
            return;
        }
        Map<String, ChampionRaceBetVO> betMap = rdMap.entrySet().stream()
                .filter(entry -> entry.getValue().getExchange() == (byte) 0)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        if (CollectionUtils.isEmpty(betMap)) {
            return;
        }
        ChampionRaceAllBetRecordsData data = game().pvp.championRace.getBizHandler().getAllBets();
        if (data == null) {
            logger.error("获取竞猜记录错误! 无法为玩家兑现竞猜奖励");
            return;
        }
        ChampionRaceSpec nowStepSpec = ChampionRaceSpec.ofNullStep(game().pvp.championRace.getSpec());
        for (ChampionRaceBetRecord betRecord : data.records) {
            ChampionRaceBetVO betVO = betMap.get(betRecord.getSpec().toString());
            if (Objects.isNull(betVO) || nowStepSpec.compareTo(betRecord.getSpec()) <= 0) {
                continue;
            }
            byte res = betVO.handleBetRecord(betRecord);
            if (res > 0) {
                addCoins(betVO.getGetCoins());
            }
        }
    }

    public void queryBetRecord() {
        ChampionRaceSpec spec = game().pvp.championRace.getSpec();
        Map<String, ChampionRaceBetVO> res = rdMap
                .entrySet()
                .stream()
                .filter(entry -> entry.getValue().getSpec().getPeriod() < spec.getPeriod()
                        || (entry.getValue().getSpec().getPeriod() == spec.getPeriod() && entry.getValue().getSpec().getRound() < spec.getRound())
                        || (spec.getStep() - entry.getValue().getSpec().getStep() > 2))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        role.sendNow(new ChampionRaceBetRecordResp(res));
    }

    public GameResult<Void> doBet(byte side) {
        GameResult<Void> r = new GameResult<>();
        if (side != GDFight.Team.A && side != GDFight.Team.B) {
            return r.fail("竞猜数据错误");
        }
        ChampionRaceSpec spec = game().pvp.championRace.getSpec();
        if (spec.getStep() != 1) {
            return r.fail("当前非竞猜阶段");
        }
        ChampionRaceSpec querySpec = ChampionRaceSpec.ofNullStep(spec);
        if (rdMap.containsKey(querySpec.toString())) {
            return r.fail("已经参与竞猜本轮,无需重复参与!");
        }
        if (rdMap.size() >= GDChampionRace.MAX_BET_TIMES) {
            return r.fail("竞猜次数不足，请在下期活动再参与");
        }
        return r;
    }

    public void onSeasonSwitch() {
        rdMap.clear();
    }

    public void addCoins(long added) {
        if (added > 0) {
            MixRes rwd = new MixRes();
            rwd.addItem(new MixResItem(GDObj.Type.NUM, GDObj.Num.CHAMPION_RACE_POINT, added));
            rwd.add(role);
            role.getGame().notice.dialogReward(role, rwd);
        }
    }
}
